/**
 * API工具函数
 * @description 提供统一的API请求处理、错误处理、认证等功能
 */

import { API_CONFIG, API_PATHS, HTTP_METHODS, HEADERS, STATUS_CODES, getApiUrl } from '@/constants/api'
import { httpGet, httpPost, httpPut, httpDelete, httpPatch } from '@/utils/httpInterceptor'
import type { ApiResponse as InterceptorResponse, ApiError as InterceptorError, RequestConfig as InterceptorConfig } from '@/utils/httpInterceptor'
import { httpGet, httpPost, httpPut, httpDelete, httpPatch } from '@/utils/httpInterceptor'
import type { ApiResponse as InterceptorResponse, ApiError as InterceptorError, RequestConfig as InterceptorConfig } from '@/utils/httpInterceptor'

// 请求配置接口
export interface RequestConfig {
    method?: string
    headers?: Record<string, string>
    body?: any
    timeout?: number
    withAuth?: boolean
    retry?: number
    retryDelay?: number
}

// 响应接口
export interface ApiResponse<T = any> {
    success: boolean
    data?: T
    error?: string
    message?: string
    code?: number
}

// 错误类型
export class ApiError extends Error {
    public status: number
    public code: string

    constructor(message: string, status: number = 500, code: string = 'UNKNOWN_ERROR') {
        super(message)
        this.name = 'ApiError'
        this.status = status
        this.code = code
    }
}

/**
 * 获取认证Token
 * @returns {string | null} 认证Token
 */
export const getAuthToken = (): string | null => {
    return localStorage.getItem('token')
}

/**
 * 设置认证Token
 * @param {string} token 认证Token
 */
export const setAuthToken = (token: string): void => {
    localStorage.setItem('token', token)
}

/**
 * 移除认证Token
 */
export const removeAuthToken = (): void => {
    localStorage.removeItem('token')
}

/**
 * 获取请求头
 * @param {boolean} withAuth 是否包含认证信息
 * @param {Record<string, string>} customHeaders 自定义请求头
 * @returns {Record<string, string>} 请求头对象
 */
export const getHeaders = (withAuth: boolean = false, customHeaders: Record<string, string> = {}): Record<string, string> => {
    const headers: Record<string, string> = {
        'Content-Type': HEADERS.CONTENT_TYPE.JSON,
        'Accept': HEADERS.CONTENT_TYPE.JSON,
        ...customHeaders
    }

    if (withAuth) {
        const token = getAuthToken()
        if (token) {
            headers[HEADERS.AUTHORIZATION] = `Bearer ${token}`
        }
    }

    return headers
}

/**
 * 处理响应
 * @param {Response} response 响应对象
 * @returns {Promise<any>} 处理后的数据
 */
export const handleResponse = async (response: Response): Promise<any> => {
    const contentType = response.headers.get('content-type')

    // 检查响应状态
    if (!response.ok) {
        let errorMessage = `HTTP ${response.status}: ${response.statusText}`

        try {
            const errorData = await response.json()
            errorMessage = errorData.message || errorData.error || errorMessage
        } catch {
            // 如果无法解析JSON，使用默认错误信息
        }

        throw new ApiError(errorMessage, response.status)
    }

    // 处理不同的内容类型
    if (contentType && contentType.includes('application/json')) {
        return await response.json()
    } else if (contentType && contentType.includes('text/')) {
        return await response.text()
    } else {
        return await response.blob()
    }
}

/**
 * 重试机制
 * @param {Function} fn 要重试的函数
 * @param {number} retries 重试次数
 * @param {number} delay 重试延迟（毫秒）
 * @returns {Promise<any>} 函数执行结果
 */
export const retry = async <T>(
    fn: () => Promise<T>,
    retries: number = 3,
    delay: number = 1000
): Promise<T> => {
    try {
        return await fn()
    } catch (error) {
        if (retries <= 0) {
            throw error
        }

        await new Promise(resolve => setTimeout(resolve, delay))
        return retry(fn, retries - 1, delay * 2)
    }
}

/**
 * 基础请求函数
 * @param {string} url 请求URL
 * @param {RequestConfig} config 请求配置
 * @returns {Promise<ApiResponse>} 响应结果
 */
export const request = async <T = any>(
    url: string,
    config: RequestConfig = {}
): Promise<ApiResponse<T>> => {
    const {
        method = HTTP_METHODS.GET,
        headers = {},
        body,
        timeout = API_CONFIG.TIMEOUT,
        withAuth = false,
        retry: retryCount = 0,
        retryDelay = 1000
    } = config

    const fullUrl = getApiUrl(url)
    const requestHeaders = getHeaders(withAuth, headers)

    const requestFn = async (): Promise<ApiResponse<T>> => {
        const controller = new AbortController()
        const timeoutId = setTimeout(() => controller.abort(), timeout)

        try {
            const requestConfig: RequestInit = {
                method,
                headers: requestHeaders,
                signal: controller.signal
            }

            if (body && method !== HTTP_METHODS.GET) {
                if (body instanceof FormData) {
                    // 如果是FormData，不设置Content-Type，让浏览器自动设置
                    delete requestHeaders['Content-Type']
                } else {
                    requestConfig.body = JSON.stringify(body)
                }
            }

            const response = await fetch(fullUrl, requestConfig)
            const data = await handleResponse(response)

            return {
                success: true,
                data,
                code: response.status
            }
        } catch (error) {
            clearTimeout(timeoutId)

            if (error instanceof ApiError) {
                return {
                    success: false,
                    error: error.message,
                    code: error.status
                }
            }

            return {
                success: false,
                error: error instanceof Error ? error.message : '网络请求失败',
                code: STATUS_CODES.INTERNAL_SERVER_ERROR
            }
        }
    }

    // 如果有重试配置，使用重试机制
    if (retryCount > 0) {
        return await retry(requestFn, retryCount, retryDelay)
    }

    return await requestFn()
}

const toApiResponse = <T>(res: InterceptorResponse<T>): ApiResponse<T> => ({
    success: res.success !== false,
    data: res.data,
    message: res.message,
    code: res.code
})

const toInterceptorConfig = (config: RequestConfig = {}): Partial<InterceptorConfig> => ({
    headers: config.headers,
    timeout: config.timeout ?? API_CONFIG.TIMEOUT,
    retryCount: config.retry,
    retryDelay: config.retryDelay
})

const toApiResponse = <T>(res: InterceptorResponse<T>): ApiResponse<T> => ({
    success: res.success !== false,
    data: res.data,
    message: res.message,
    code: res.code
})

const toInterceptorConfig = (config: RequestConfig = {}): Partial<InterceptorConfig> => ({
    headers: config.headers,
    timeout: config.timeout ?? API_CONFIG.TIMEOUT,
    retryCount: config.retry,
    retryDelay: config.retryDelay
})

/**
 * GET请求
 * @param {string} url 请求URL
 * @param {any} params 查询参数
 * @param {RequestConfig} config 请求配置
 * @returns {Promise<ApiResponse>} 响应结果
 */
export const get = async <T = any>(url: string, params?: any, config: RequestConfig = {}): Promise<ApiResponse<T>> => {
    try {
        const res = await httpGet<T>(getApiUrl(url), params, toInterceptorConfig(config))
        return toApiResponse(res)
    } catch (e) {
        const err = e as InterceptorError
        return { success: false, error: err.message, code: (err as any).code }
    }
}

/**
 * POST请求
 * @param {string} url 请求URL
 * @param {any} data 请求数据
 * @param {RequestConfig} config 请求配置
 * @returns {Promise<ApiResponse>} 响应结果
 */
export const post = async <T = any>(url: string, data?: any, config: RequestConfig = {}): Promise<ApiResponse<T>> => {
    try {
        const res = await httpPost<T>(getApiUrl(url), data, toInterceptorConfig(config))
        return toApiResponse(res)
    } catch (e) {
        const err = e as InterceptorError
        return { success: false, error: err.message, code: (err as any).code }
    }
    export const post = async <T = any>(url: string, data?: any, config: RequestConfig = {}): Promise<ApiResponse<T>> => {
        try {
            const res = await httpPost<T>(getApiUrl(url), data, toInterceptorConfig(config))
            return toApiResponse(res)
        } catch (e) {
            const err = e as InterceptorError
            return { success: false, error: err.message, code: (err as any).code }
        }
    }

    /**
     * PUT请求
     * @param {string} url 请求URL
     * @param {any} data 请求数据
     * @param {RequestConfig} config 请求配置
     * @returns {Promise<ApiResponse>} 响应结果
     */
    export const put = async <T = any>(url: string, data?: any, config: RequestConfig = {}): Promise<ApiResponse<T>> => {
        try {
            const res = await httpPut<T>(getApiUrl(url), data, toInterceptorConfig(config))
            return toApiResponse(res)
        } catch (e) {
            const err = e as InterceptorError
            return { success: false, error: err.message, code: (err as any).code }
        }
        export const put = async <T = any>(url: string, data?: any, config: RequestConfig = {}): Promise<ApiResponse<T>> => {
            try {
                const res = await httpPut<T>(getApiUrl(url), data, toInterceptorConfig(config))
                return toApiResponse(res)
            } catch (e) {
                const err = e as InterceptorError
                return { success: false, error: err.message, code: (err as any).code }
            }
        }

        /**
         * DELETE请求
         * @param {string} url 请求URL
         * @param {RequestConfig} config 请求配置
         * @returns {Promise<ApiResponse>} 响应结果
         */
        export const del = async <T = any>(url: string, config: RequestConfig = {}): Promise<ApiResponse<T>> => {
            try {
                const res = await httpDelete<T>(getApiUrl(url), toInterceptorConfig(config))
                return toApiResponse(res)
            } catch (e) {
                const err = e as InterceptorError
                return { success: false, error: err.message, code: (err as any).code }
            }
            export const del = async <T = any>(url: string, config: RequestConfig = {}): Promise<ApiResponse<T>> => {
                try {
                    const res = await httpDelete<T>(getApiUrl(url), toInterceptorConfig(config))
                    return toApiResponse(res)
                } catch (e) {
                    const err = e as InterceptorError
                    return { success: false, error: err.message, code: (err as any).code }
                }
            }

            /**
             * PATCH请求
             * @param {string} url 请求URL
             * @param {any} data 请求数据
             * @param {RequestConfig} config 请求配置
             * @returns {Promise<ApiResponse>} 响应结果
             */
            export const patch = async <T = any>(url: string, data?: any, config: RequestConfig = {}): Promise<ApiResponse<T>> => {
                try {
                    const res = await httpPatch<T>(getApiUrl(url), data, toInterceptorConfig(config))
                    return toApiResponse(res)
                } catch (e) {
                    const err = e as InterceptorError
                    return { success: false, error: err.message, code: (err as any).code }
                }
                export const patch = async <T = any>(url: string, data?: any, config: RequestConfig = {}): Promise<ApiResponse<T>> => {
                    try {
                        const res = await httpPatch<T>(getApiUrl(url), data, toInterceptorConfig(config))
                        return toApiResponse(res)
                    } catch (e) {
                        const err = e as InterceptorError
                        return { success: false, error: err.message, code: (err as any).code }
                    }
                }

                /**
                 * 文件上传
                 * @param {string} url 上传URL
                 * @param {File | File[]} files 文件或文件数组
                 * @param {Record<string, any>} additionalData 额外数据
                 * @param {RequestConfig} config 请求配置
                 * @returns {Promise<ApiResponse>} 响应结果
                 */
                export const upload = async <T = any>(
                    url: string,
                    files: File | File[],
                    additionalData: Record<string, any> = {},
                    config: RequestConfig = {}
                ): Promise<ApiResponse<T>> => {
                    const formData = new FormData()

                    // 添加文件
                    if (Array.isArray(files)) {
                        files.forEach((file, index) => {
                            formData.append(`files[${index}]`, file)
                        })
                    } else {
                        formData.append('file', files)
                    }

                    // 添加额外数据
                    Object.entries(additionalData).forEach(([key, value]) => {
                        formData.append(key, typeof value === 'object' ? JSON.stringify(value) : String(value))
                    })

                    return request<T>(url, {
                        ...config,
                        method: HTTP_METHODS.POST,
                        body: formData,
                        headers: {
                            ...config.headers,
                            // 不设置Content-Type，让浏览器自动设置multipart/form-data
                        }
                    })
                }

                /**
                 * 下载文件
                 * @param {string} url 下载URL
                 * @param {string} filename 文件名
                 * @param {RequestConfig} config 请求配置
                 * @returns {Promise<void>}
                 */
                export const download = async (
                    url: string,
                    filename?: string,
                    config: RequestConfig = {}
                ): Promise<void> => {
                    const response = await request(url, {
                        ...config,
                        headers: {
                            ...config.headers,
                            'Accept': '*/*'
                        }
                    })

                    if (response.success && response.data instanceof Blob) {
                        const blob = response.data
                        const downloadUrl = window.URL.createObjectURL(blob)
                        const link = document.createElement('a')
                        link.href = downloadUrl
                        link.download = filename || 'download'
                        document.body.appendChild(link)
                        link.click()
                        document.body.removeChild(link)
                        window.URL.revokeObjectURL(downloadUrl)
                    }
                }

                // 导出API路径常量，方便在store中使用
                export { API_PATHS, API_CONFIG, HTTP_METHODS, HEADERS, STATUS_CODES }
